package com.daijt.mobile.restful;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.daijt.mobile.persistence.CheckList;
import com.daijt.mobile.persistence.ListItem;
import com.daijt.mobile.persistence.User;
import com.daijt.mobile.service.CheckListService;
import com.daijt.mobile.service.ListItemService;
import com.daijt.mobile.service.UserService;

@Controller
@RequestMapping("/checklists")
public class CheckListRestfulService {
	
	private static Logger log = Logger.getLogger(CheckListRestfulService.class);
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private CheckListService checklistService;
	
	@Autowired
	private ListItemService listItemService;
	
	
	@Transactional
	@RequestMapping(method=RequestMethod.POST, value="/updateUser", headers="Accept=application/json")
	public @ResponseBody Map<String, ? extends Object> updateUser(@RequestBody User user, HttpServletResponse response) {
		
		if (log.isDebugEnabled()) {
			log.debug("### RETRIEVE USER INFO [" + user.getUserId() + "/" + user.getEmail() + "/" + user.getPassword() + "]");
		}
		
		User userAfter = null;
		
		try {
			if (user.getUserId() != 0) {
				
				if (log.isDebugEnabled()) {
					log.debug("### UPDATE EXISTING USER WITH ID " + user.getUserId());
				}
				
				userAfter = userService.updateUser(user);
			}
			else {
				String email = user.getEmail();
				
				User existingUsr = userService.getUserByEmail(email);
				
				if (existingUsr != null) {
					if (log.isDebugEnabled()) {
						log.debug("### FOUND USER BY EMAIL. USER ID " + user.getUserId());
					}
					
					if (!existingUsr.getPassword().equals(user.getPassword())) {
						String errorMsg = "Password doesn't match";
						if (log.isInfoEnabled()) {
							log.info(errorMsg + " for user " + user.getEmail());
						}
						response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
						return Collections.singletonMap("error", errorMsg);
					}
					
					existingUsr.setPassword(user.getPassword());
				}
				else {
					if (log.isDebugEnabled()) {
						log.debug("### CREATE NEW USER ###");
					}
					existingUsr = new User();
					existingUsr.setEmail(user.getEmail());
					existingUsr.setPassword(user.getPassword());
				}
				
				userAfter = userService.updateUser(existingUsr);
				
			}
		}
		catch (Exception e) {
			log.error("Failed to create or update user", e);
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			return Collections.singletonMap("error", e.getMessage());
		}
		
		return Collections.singletonMap("user", userAfter);
	}

	@Transactional
	@RequestMapping(method=RequestMethod.GET, value="/listAll")
	public @ResponseBody Map<String, ? extends Object> listAll(@RequestParam String userName, @RequestParam String password, HttpServletResponse response) {
		
		if (log.isDebugEnabled()) {
			log.debug("### Retrieve all lists under username: " + userName + " password: " + password);
		}
		
		User currentUsr = userService.getUserByEmail(userName);
		
		if (currentUsr == null || !currentUsr.getPassword().equalsIgnoreCase(password)) {
			if (log.isInfoEnabled()) {
				log.info("Authentication failed for listAll service with userName " + userName);
			}
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			return Collections.singletonMap("error", "Invalid user name or password");
		}
		
		List<CheckList> lists = checklistService.getCheckListsByUser(currentUsr.getUserId());
		
		if (log.isDebugEnabled()) {
			log.debug("### Found lists number: " + lists.size());
		}
		
		return Collections.singletonMap("lists", lists);
	}
	
	@Transactional
	@RequestMapping(method=RequestMethod.POST, value="/uploadList", headers="Accept=application/json")
	public @ResponseBody Map<String, ? extends Object> uploadList(@RequestBody CheckList list, HttpServletResponse response) {
		CheckList updatedList = null;
		
		try {
			User user = userService.getUserById(list.getOwner().getUserId());
			
			if (user == null || !user.getPassword().equals(list.getOwner().getPassword())) {
				if (log.isInfoEnabled()) {
					log.info("Authentication failed for uploadList service with userName " + list.getOwner().getEmail());
				}
				response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
				return Collections.singletonMap("error", "Invalid user name or password");
			}
			
			long listId = list.getId();
			
			long version = list.getVersion();
			list.setVersion(version + 1);
			
			if (listId == 0) {
				if (log.isInfoEnabled()) {
					log.info("Insert new list into the server: " + list.getListName());
				}
				
				checklistService.persistCheckList(list);
				
				listId = list.getId();
				
				List<ListItem> items = list.getItems();
				
				for (ListItem item : items) {
					item.setListId(listId);
				}
				
				listItemService.insertListItems(items);
		
			}
			else {
				
				if (log.isInfoEnabled()) {
					log.info("Update existing list: " + list.getId() + " " + list.getListName());
				}
				
				updatedList = checklistService.getCheckListById(listId);
				updatedList.setListName(list.getListName());
				updatedList.setListType(list.getListType());
				updatedList.setStatus(list.getStatus());
				updatedList.setVersion(list.getVersion());
				
				checklistService.persistCheckList(updatedList);
				
				// listItemService.clearItemsFromList(listId);
				
				List<ListItem> items = list.getItems();
				
				for (ListItem item : items) {
					item.setListId(listId);
				}
				
				listItemService.mergeListItems(listId, items);
				
			}
			
			updatedList = checklistService.getFullCheckListById(listId);
		}
		catch (Exception e) {
			log.error("Failed to save or update list: ", e);
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			return Collections.singletonMap("error", e.getMessage());
		}
		
		return Collections.singletonMap("list", updatedList);
	}
	
	@Transactional
	@RequestMapping(method = RequestMethod.DELETE, value="/deleteList")
	public @ResponseBody Map<String, ? extends Object> deleteList(@RequestParam String userName, @RequestParam String password, 
			@RequestParam long listId, HttpServletResponse response) {
		
		try {
			User user = userService.getUserByEmail(userName);
			
			if (user == null || !user.getPassword().equals(password)) {
				if (log.isInfoEnabled()) {
					log.info("Authentication failed for deleteList service with userName " + userName);
				}
				response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
				return Collections.singletonMap("error", "Invalid user name or password");
			}
			
			CheckList list = checklistService.getCheckListById(listId);
			
			if (list != null) {
				checklistService.removeCheckList(list);
			}
		}
		catch (Exception e) {
			log.error("Failed to save or update list: ", e);
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
			return Collections.singletonMap("error", e.getMessage());
		}
		
		return Collections.singletonMap("info", "List has been deleted on server.");
	}
}
